#ifndef MEMORY_
#define MEMORY_

#include "typedef.hpp"
#include <map>
#include <iostream>
#include <cstdint>

enum ACCESS : uint8_t
{
	R = 1,
	W = 2,
	X = 4,
	P = 8
};
enum MESI : uint8_t
{
	M = 1,
	E = 2,
	S = 4,
	I = 8
};

// Cache结构
struct CacheLine
{ // Cache行
	uint8_t data[64];
	uint8_t MESImeta;

	uint8_t *operator&() { return data; }
};
class CacheBlock
{ // Cache组
private:
	pair<uint64_t, CacheLine> mem[4];
	int ptr;

public:
	CacheBlock() = default;
	~CacheBlock() = default;

	bool read(uint64_t, uint8_t);
	bool write(uint64_t, uint8_t, size_t);
	void load(uint64_t);
	void store(uint64_t index);
};
class CacheSet
{ // Cache层，3.0版本只实现一级Cache
private:
	CacheBlock *cache;
	size_t count;

public:
	CacheSet() : count(0) { cache = new CacheBlock[0]; }
	CacheSet(const size_t size) : count(size) { cache = new CacheBlock[size]; }
	~CacheSet() { delete[] cache; }
	bool read(uint64_t, uint8_t);
	bool write(uint64_t, uint8_t, size_t);
	void load(uint64_t);
	void store(uint64_t);
};
class Cache
{ // Cache
private:
	CacheSet L1I, L1D;

public:
	Cache() = default;
	~Cache() = default;
	void read(bool);
	void write(size_t);
	void load(bool);
	// 自动store，不需要额外函数
};

// TLB结构
class TLB
{
private:
	pair<uint64_t, uint64_t> tlb[256];
	inline pair<bool, uint64_t> operator[](uint64_t vpage) { return pair<bool, uint64_t>{vpage == tlb[vpage & 0xff].first, tlb[vpage & 0xff].second}; }
	inline uint8_t getAccess(uint64_t item) { return (item >> 40) & 0x0f; }
	inline uint8_t getMeta(uint64_t item) { return (item >> 48) & 0x0f; }
	inline uint64_t getPageID(uint64_t item) { return item & 0xfffffffff; }

public:
	TLB() = default;
	~TLB() = default;
	void addtrans(uint8_t);
	void update();
};

// IOChannel结构
enum TYPE
{
	RO, // 单输入
	WO, // 单输出
	RW, // 双向
	In, // std::cin特化
	Out // std::cout特化
};
struct Device
{
	TYPE typid;
	void *devicePtr;

	Device() = default;
	Device(TYPE, const char * = nullptr);
};
class IOChannel
{
private:
	std::map<uint64_t, Device *> devices;

public:
	IOChannel() = default;
	~IOChannel() = default;
	void addDevice(const char *, uint64_t, TYPE);
	void delDevice(uint64_t);
	void read(const size_t);
	void write(const size_t);
};

class MemControl
{
private:
	Cache *cache;
	TLB *tlb;
	IOChannel *io;

public:
	MemControl();
	~MemControl();
	// Cache接口
	void read(const size_t, bool = false);
	void write(const size_t);
	// IO接口
	inline void mount(const char *filename, const uint64_t id, const TYPE IOt) { io->addDevice(filename, id, IOt); }
	inline void umount(const uint64_t id) { io->delDevice(id); }
	void readIO();
	void writeIO();
	// TLB接口
	void addtrans(uint8_t);
};

#endif